﻿#region using statements

using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

using NGen;
using NGen.Managers.GUI;
using NGen.Managers.GameState;
using NGen.Managers.Input;

using Nuclex.UserInterface;
using Nuclex.UserInterface.Controls;
using Nuclex.UserInterface.Controls.Desktop;

using XNAGameDemo.GameStates;

#endregion

namespace XNAGameDemo.GUI
{
	/// <summary>
	/// 	GUI window to manage changing9 states
	/// </summary>
	public class GUIElementStateSwitch : GUIElement, IKeyboardListener
	{
		#region local fields

		private readonly ButtonControl m_nextButton = new ButtonControl();

		private readonly ButtonControl m_previousButton = new ButtonControl();

		private readonly ButtonControl m_quitButton = new ButtonControl();

		private readonly ListControl m_stateSelectList = new ListControl();

		private readonly ButtonControl m_toggleWindowButton = new ButtonControl();

		private readonly WindowControl m_window = new WindowControl();

		private LabelControl m_textLabel = new LabelControl();

		#endregion

		#region local methods

		/// <summary>
		/// 	This method is the one used to receive notifications of a game
		/// 	state change. This class instance subscribes to notification
		/// 	in the initialize method
		/// </summary>
		/// <param name = "p_stateName">the name of the new state</param>
		protected void _OnGameStateChanged(string p_stateName) {
			var oldStateNum = m_stateSelectList.SelectedItems[0];
			int newStateNum;
			switch(p_stateName) {
				default:
				case "GameStateIntro":
					newStateNum = 0;
					break;
				case "GameStateMenu":
					newStateNum = 1;
					break;
				case "GameStatePlay1":
					newStateNum = 2;
					break;
				case "GameStatePlay2":
					newStateNum = 3;
					break;
				case "GameStatePlay3":
					newStateNum = 4;
					break;
				case "GameStateGameOver":
					newStateNum = 5;
					break;
				case "GameStateCredits":
					newStateNum = 6;
					break;
			}

			//
			if(oldStateNum != newStateNum) {
				m_stateSelectList.SelectedItems[0] = newStateNum;
			}
		}

		/// <summary>
		/// 	Gets a state associated with a specific entry in the list
		/// </summary>
		/// <param name = "p_listSelectionNum">the entry number</param>
		/// <returns>the gamestate associated with the passed in entry</returns>
		protected GameState _GetState(int p_listSelectionNum) {
			switch(p_listSelectionNum) {
				case 0:
					return new GameStateIntro();
				case 1:
					return new GameStateMenu();
				case 2:
					return new GameStatePlay1();
				case 3:
					return new GameStatePlay2();
				case 4:
					return new GameStatePlay3();
				case 5:
					return new GameStateGameOver();
				case 6:
					return new GameStateCredits();
			}
			return new GameStateIntro();
		}

		/// <summary>
		/// 	Called whenever the next button is clicked
		/// </summary>
		protected void _NextButtonClick(object p_sender, EventArgs p_e) {
			var newStateNum = m_stateSelectList.SelectedItems[0] < 6 ? 1 + m_stateSelectList.SelectedItems[0] : 0;
			GameEngine.GetService<IManagerGameState>().ChangeState(_GetState(newStateNum));
		}

		/// <summary>
		/// 	Called whenever the previous button is clicked
		/// </summary>
		protected void _PreviousButtonClick(object p_sender, EventArgs p_e) {
			var newStateNum = m_stateSelectList.SelectedItems[0] > 0 ? -1 + m_stateSelectList.SelectedItems[0] : 6;
			GameEngine.GetService<IManagerGameState>().ChangeState(_GetState(newStateNum));
		}

		/// <summary>
		/// 	Called whenever the clicked button is clicked
		/// </summary>
		protected void _QuitButtonClick(object p_sender, EventArgs p_e) {
			GameEngine.Exit();
		}

		/// <summary>
		/// 	Called whenever the toggle button is clicked
		/// </summary>
		protected void _ToggleWindowButtonClick(object p_sender, EventArgs p_e) {
			if(m_window.IsOpen) {
				_Children.Remove(m_window);
			} else {
				_Children.Add(m_window);
			}
		}

		/// <summary>
		/// 	Called whenever the list box changes its selection value
		/// </summary>
		protected void _StateSelectChange(object p_sender, EventArgs p_e) {
			//this if check is here because this gets called 4 times if you
			//click on the name within the list box because of the way
			//the selection list is coded (stupid, i know)
			if(GameEngine.GetService<IManagerGameState>().CurrentStateName !=
			   _GetState(m_stateSelectList.SelectedItems[0]).StateName) {
				GameEngine.GetService<IManagerGameState>().ChangeState(_GetState(m_stateSelectList.SelectedItems[0]));
			}
		}

		#endregion

		#region GUIElement implementation

		/// <summary>
		/// 	Initalizes the gui. Adds all the controls to this layouts Desktop
		/// </summary>
		protected override void _Initialize() {
			//subscribe to game state change notifications
			GameEngine.GetService<IManagerGameState>().GameStateChangedEvent += _OnGameStateChanged;
			//subscribe to get keyboard events
			GameEngine.GetService<IManagerInput>().AddKeyboardListener(this);

			//setup the toggle button
			m_toggleWindowButton.Bounds = new UniRectangle(new UniScalar(0.01f, 0.0f), new UniScalar(0.01f, 0.0f), new UniScalar(150), new UniScalar(30));
			m_toggleWindowButton.Text = "Toggle Window";
			m_toggleWindowButton.Pressed += _ToggleWindowButtonClick;
			_Children.Add(m_toggleWindowButton);

			//setup the window
			m_window.Bounds = new UniRectangle(15.0f, 45.0f, 215.0f, 250.0f);
			m_window.Title = "State Select";
			_Children.Add(m_window);

			//********************************************
			//all of the following are added to the window

			//setup next button, add to window
			m_nextButton.Bounds = new UniRectangle(new UniScalar(0.9f, -55.0f), new UniScalar(0.9f, -12.5f), new UniScalar(55.0f), new UniScalar(25));
			m_nextButton.Enabled = true;
			m_window.Children.Add(m_nextButton);
			m_nextButton.Pressed += _NextButtonClick;
			m_nextButton.Text = "Next";

			//setup previous button, add to window
			m_previousButton.Bounds = new UniRectangle(new UniScalar(0.1f, 0.0f), new UniScalar(0.9f, -12.5f), new UniScalar(55.0f), new UniScalar(25));
			m_previousButton.Enabled = true;
			m_window.Children.Add(m_previousButton);
			m_previousButton.Pressed += _PreviousButtonClick;
			m_previousButton.Text = "Prev";

			//setup quit button, add to window
			m_quitButton.Bounds = new UniRectangle(new UniScalar(0.5f, -27.5f), new UniScalar(0.9f, -12.5f), new UniScalar(55.0f), new UniScalar(25));
			m_quitButton.Enabled = true;
			m_window.Children.Add(m_quitButton);
			m_quitButton.Pressed += _QuitButtonClick;
			m_quitButton.Text = "Quit";

			//setup the selection list, add to window
			m_stateSelectList.Bounds = new UniRectangle(new UniScalar(0.1f, 0.0f), new UniScalar(0.2f, 0.0f), new UniScalar(0.8f, 0.0f), new UniScalar(0.6f, 0.0f));
			m_stateSelectList.Items.Add("(F1) Intro");
			m_stateSelectList.Items.Add("(F2) Menu");
			m_stateSelectList.Items.Add("(F3) Play1");
			m_stateSelectList.Items.Add("(F4) Play2");
			m_stateSelectList.Items.Add("(F5) Play3");
			m_stateSelectList.Items.Add("(F6) Game Over");
			m_stateSelectList.Items.Add("(F7) Credits");
			m_stateSelectList.SelectionMode = //allows single item selection
				ListSelectionMode.Single;
			m_stateSelectList.SelectedItems.Add(0);
			m_stateSelectList.SelectionChanged += _StateSelectChange;
			m_window.Children.Add(m_stateSelectList);
		}

		/// <summary>
		/// 	Update this element for this frame
		/// </summary>
		/// <param name = "p_gameTime">snapshot of timing values</param>
		protected override void Update(GameTime p_gameTime) {}

		/// <summary>
		/// 	Perform any cleanup operations before this element is destroyed
		/// </summary>
		protected override void _Cleanup() {
			//unsubscribe to game state change notifications
			GameEngine.GetService<IManagerGameState>().GameStateChangedEvent -= _OnGameStateChanged;
		}

		#endregion

		#region IKeyboardListener implementation

		public void KeyPressed(Keys p_key) {}

		public void KeyReleased(Keys p_key) {
			switch(p_key) {
				case Keys.F1:
					m_stateSelectList.SelectedItems[0] = 0;
					break;
				case Keys.F2:
					m_stateSelectList.SelectedItems[0] = 1;
					break;
				case Keys.F3:
					m_stateSelectList.SelectedItems[0] = 2;
					break;
				case Keys.F4:
					m_stateSelectList.SelectedItems[0] = 3;
					break;
				case Keys.F5:
					m_stateSelectList.SelectedItems[0] = 4;
					break;
				case Keys.F6:
					m_stateSelectList.SelectedItems[0] = 5;
					break;
				case Keys.F7:
					m_stateSelectList.SelectedItems[0] = 6;
					break;
			}
		}

		#endregion
	}
}